package cc.rengu.igas.channel.upac.core.service.trans;

import cc.rengu.igas.channel.upac.common.constant.UpacConfigConstant;
import cc.rengu.igas.channel.upac.common.constant.UpacParamConstant;
import cc.rengu.igas.channel.upac.common.constant.UpacTreeNodeConstant;
import cc.rengu.igas.channel.upac.common.util.UpacSecurityUtil;
import cc.rengu.igas.channel.upac.core.model.ChnlBizResponse;
import cc.rengu.igas.channel.upac.core.service.base.NoticeService;
import cc.rengu.igas.channel.upac.facade.request.UpacPayOpenNoticeRequest;
import cc.rengu.igas.channel.upac.facade.response.UpacPayOpenNoticeResponse;
import cc.rengu.igas.share.facade.request.UpacSignResultNoticeRequest;
import cc.rengu.igas.share.facade.response.UpacSignResultNoticeResponse;
import cc.rengu.igas.share.facade.result.Result;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.DstChannelCfgMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstChannelCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.CertInfo;
import cc.rengu.oltp.service.common.entity.DstChannelCfg;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 银联全渠道支付开通通知服务
 * Created by 王成 on 2018/6/3.
 */
public class PayOpenNoticeService extends NoticeService {

    @Override
    protected Object beforeBizProcess() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        UpacPayOpenNoticeRequest upacPayOpenNoticeRequest = new UpacPayOpenNoticeRequest();
        ConvertUtil.convertOutput(upacPayOpenNoticeRequest);
        String instId = upacPayOpenNoticeRequest.getHeader().getInstId();
        CertInfo encryptCertInfo = null;
        /* 若有上送卡号，先解密卡号 */
        if (!StringUtil.isEmptyOrNull(upacPayOpenNoticeRequest.getPayAcctNo())) {
            SysParamService sysParamService = new SysParamServiceImpl();
            /* 获取银联全渠道报文字体集类型 */
            SysParam sysParam = sysParamService.getSysParamInfo(instId, UpacConfigConstant.UPAC_CONF_NODE, UpacConfigConstant.UPAC_ENCODING);
            if (sysParam != null) {
                xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.version, sysParam.getParamValue());
            }
            String encoding = (null == sysParam) ? UpacParamConstant.UTF_8_ENCODING : sysParam.getParamValue();
            /* 获取银联全渠道卡号加密方式 */
            sysParam = sysParamService.getSysParamInfo(instId, UpacConfigConstant.UPAC_CONF_NODE, UpacConfigConstant.UPAC_ACCT_ENC);
            String acctNoEncType = null == sysParam ? AppParamConstant.NO : sysParam.getParamValue();
            if (AppParamConstant.YES.equals(acctNoEncType)) {
                /* 获取敏感信息解密证书,查询通道配置表 */
                DstChannelCfgMapper dstChannelCfgMapper = new DstChannelCfgMapperImpl();
                List<DstChannelCfg> dstChannelCfgList = dstChannelCfgMapper.selectDstChannelCfgBydstChannelId(instId, ChannelEnum.UPAC.getChannelType());
                if (dstChannelCfgList == null || dstChannelCfgList.isEmpty()) {
                    throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
                }
                dstChannelCfgList = dstChannelCfgList.stream().filter(item -> item.getProviderMchntNo().equals(upacPayOpenNoticeRequest.getUpacMchntNo())).collect(Collectors.toList());
                if (dstChannelCfgList.isEmpty()) {
                    throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
                }
                xmlTreeUtil.setXmlTreeObjectValue(UpacTreeNodeConstant.DST_CHANNEL_CFG, dstChannelCfgList.get(0));

                /* 根据通道安全计划获取安全计划 */
                SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
                List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelCfgList.get(0).getSecPlanId());
                if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
                    /* 解密证书 */
                    Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(UpacParamConstant.DECRYPT_CERT_TYPE)).findFirst();
                    if (secPlanInfoOpt.isPresent()) {
                        CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                        encryptCertInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getInstId() + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                    }
                }
                if (encryptCertInfo == null) {
                    rglog.error("获取商户<{}>的解密证书失败", upacPayOpenNoticeRequest.getUpacMchntNo());
                    throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
                }
                xmlTreeUtil.setXmlTreeObjectValue("encryptCertInfo", encryptCertInfo);
                String acctNo = UpacSecurityUtil.decryptData(upacPayOpenNoticeRequest.getPayAcctNo(), encryptCertInfo.getCertValue(), encoding);
                rglog.debug("acctNo=[{}]", acctNo);
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.PAYER_ACCT_INFO, acctNo);
                upacPayOpenNoticeRequest.setPayAcctNo(acctNo);
            }
        }
        return upacPayOpenNoticeRequest;
    }

    @Override
    protected ChnlBizResponse callBizService(Object request) throws Exception {
        UpacPayOpenNoticeRequest upacPayOpenNoticeRequest = (UpacPayOpenNoticeRequest) request;
        UpacPayOpenNoticeResponse upacPayOpenNoticeResponse = new UpacPayOpenNoticeResponse();

        String customerInfo = new String(Base64.decodeBase64(upacPayOpenNoticeRequest.getCustomerInfoStr()));
        rglog.info("customerInfo=[{}]", customerInfo);
        Map<String, String> customerMap = UpacSecurityUtil.convertResultString2Map(customerInfo.substring(1, customerInfo.length() - 1));
        upacPayOpenNoticeRequest.setAcqReserved(JSON.toJSONString(customerMap));

        /* 调用Share模块中的银联二维码业务公共处理服务 */
        UpacSignResultNoticeRequest upacSignResultNoticeRequest = new UpacSignResultNoticeRequest();
        BeanUtil.beanCopy(upacPayOpenNoticeRequest, upacSignResultNoticeRequest);
        upacSignResultNoticeRequest.getHeader().setTxnNum("T00SH006");
        upacSignResultNoticeRequest.getHeader().setTraceNo(ChannelEnum.UPAC.getChannelType() + DateUtil.getCurrentDateTime("yyyyMMddHHmmssSSS") + RandomUtil.randomNumStr(10));
        DubboService dubboService = new DubboServiceImpl();
        Result<UpacSignResultNoticeResponse> callResult = (Result<UpacSignResultNoticeResponse>) dubboService.callDubboService("upacUnifiedService", "payOpenNotice", upacSignResultNoticeRequest);
        if (null != callResult) {
            UpacSignResultNoticeResponse upacSignResultNoticeResponse = callResult.getResult();
            BeanUtil.beanCopy(upacSignResultNoticeResponse, upacPayOpenNoticeResponse);
        }

        /* 组装应答报文 */
        ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
        chnlBizResponse.setResult(upacPayOpenNoticeResponse);
        return chnlBizResponse;
    }

    @Override
    protected void afterBizProcess(ChnlBizResponse response) throws Exception {
        UpacPayOpenNoticeResponse upacPayOpenNoticeResponse = (UpacPayOpenNoticeResponse) response.getResult();
        ConvertUtil.convertInput(upacPayOpenNoticeResponse);
    }
}
